#!/usr/bin/python

import pygame


# Tracks a 2 dimensional collision map
class CollisionMap2d:

    # Obvious
    def __init__(self, width=1, height=1):
        # Initialize collision map to empty
        self.m_collisionMap = [[set() for row in range(height)] for col in range(width)]

    # Obvious
    def cleanup(self):
        return None

    # Resize the collision map
    def resize(self, width, height):
        # Allocate new map
        newCollisionMap = [[set() for row in range(height)] for col in range(width)]

        # Calculate copy dimensions
        copyWidth = width
        if len(self.m_collisionMap) < copyWidth:
            copyWidth = len(self.m_collisionMap)
        copyHeight = height
        if len(self.m_collisionMap[0]) < copyHeight:
            copyHeight = len(self.m_collisionMap[0])

        # Copy
        for col in range(copyWidth):
            for row in range(copyHeight):
                newCollisionMap[col][row] = self.m_collisionMap[col][row]

        # Assign
        self.m_collisionMap = newCollisionMap
    
    # Add an entity to the collision map
    def addEntity(self, entity):
        (x,y) = entity.getPosition()
        (width,height) = entity.getSize()
        for w in range(width):
            for h in range(height):
                try:
                    self.m_collisionMap[x+w][y+h].add(entity)
                except IndexError:
                    pass
                except KeyError:
                    pass

    # Remove an entity from the collision map
    def removeEntity(self, entity):
        (x,y) = entity.getPosition()
        (width,height) = entity.getSize()
        for w in range(width):
            for h in range(height):
                try:
                    self.m_collisionMap[x+w][y+h].remove(entity)
                except IndexError:
                    pass
                except KeyError:
                    pass

    # Move an entity on the collision map
    def moveEntity(self, entity, (newx, newy)):
        # TODO: optimize this
        (oldx, oldy) = entity.getPosition()
        (width, height) = entity.getSize()
        # Remove old
        for w in range(width):
            for h in range(height):
                try:
                    self.m_collisionMap[oldx+w][oldy+h].remove(entity)
                except IndexError:
                    pass
                except KeyError:
                    pass
        # Add new
        for w in range(width):
            for h in range(height):
                try:
                    self.m_collisionMap[newx+w][newy+h].add(entity)
                except IndexError:
                    pass
                except KeyError:
                    pass


    
    # Change entity's size on the collision map
    def changeEntitySize(self, entity):
        # Same logic as add entity
        (x,y) = entity.getPosition()
        (width,height) = entity.getSize()
        for w in range(width):
            for h in range(height):
                try:
                    self.m_collisionMap[x+w][y+h].add(entity)
                except KeyError:
                    pass
        

    # Check wiether an entity can move to the specified location
    def canEntityMoveTo(self, entity, (x, y), ignoreEntities=[]):
        (width,height) = entity.getSize()
        for w in range(width):
            for h in range(height):
                for otherEntity in self.m_collisionMap[x+w][y+h]:
                    # Can't collide with ourself
                    if otherEntity == entity:
                        continue
                    # Check if other entity is even collidable
                    if not(otherEntity.isCollidable()):
                        continue
                    # Check ignore entities list
                    ignore = False
                    for ignoreEntity in ignoreEntities:
                        if otherEntity == ignoreEntity:
                            ignore = True
                            break
                    if not(ignore):
                        return (False, otherEntity)
        return (True, None)


    # Check if a tile is occupied
    def isTileOccupied(self, x, y):
        return (len(self.getTileOccupants(x,y)) > 0)

    # Retrieve tile occupants (set)
    def getTileOccupants(self, x, y):
        return self.m_collisionMap[x][y]


